package util;


/**
 * Stemmer, implementing the Spanish Porter Stemming Algorithm. The 
 * SpanishStemmer class transforms a word into its root form. The original paper is in
 * Porter, 1980, An algorithm for suffix stripping, Program, Vol. 14, no. 3, 
 * pp 130-137, See also http://www.tartarus.org/~martin/PorterStemmer
 * <p>
 * http://snowball.tartarus.org/ 
 */

public class SpanishStemmer extends StemmerAnalyzer {
	
	boolean pstep0 = false;
	boolean pstep1 = false;
	boolean pstep2a = false;
	boolean pstep2b = false;
	boolean pstep3 = false;

	/**
	 * Step 0. Attached pronoum.
	 * @return
	 * @throws Exception
	 */
	private boolean step0() throws Exception {
		int ctr;
		try {
			//delete if in R2
			String[] suffixes = {"me","se","sela","selo","selas","selos","la",
					"le","lo","las","les","los","nos"}; 					

			String[] list = {"i\u00E9ndo","\u00E1ndo","\u00E1r","\u00E9r","\u00EDr",
					"iendo","ando","ar","er","ir",
					"yendo"}; 
			
			ctr = findLongest(suffixes, getRV());
			if (ctr != -1) {
				for (int idx = 0; idx < list.length; idx++) {
					if (getRV().endsWith(list[idx]+suffixes[ctr])) {
						if (list[idx].equalsIgnoreCase("yendo")) {
							if ((getRV().endsWith("u"+list[idx]+suffixes[ctr])) ||
  								 (getWordRV().endsWith("u"))) {
								setRV(delete(getRV(),suffixes[ctr])); setPrv(true);
								if (isLog()) System.out.println("0");
								return true;
							}
						} else {
							if ((idx == 0) || (idx == 2) || (idx == 3) || (idx == 4))
								setRV(delete(getRV(),list[idx]+suffixes[ctr])); 
							else
								setRV(delete(getRV(),suffixes[ctr])); 
							setPrv(true);
							if (isLog()) System.out.println("1");
							return true;
						}
					}
				}
			}
		} catch (Exception exc) {
			throw new Exception ("Context: step0 method. Error: "+exc.getMessage());
		}
		return false;
	}

	/**
	 * Step 1. Standard suffix removal.
	 * @return
	 * @throws Exception
	 */
	private boolean step1() throws Exception {
		try {
			//delete if in R2
			String[] list1 = {"anza","anzas","ico","ica","icos","icas","ismo",
					"ismos","able","ables","ible","ibles","ista","istas",
					"oso","osa","osos","osas","amiento","amientos","imiento",
					"imientos"};
			if (deleteR2(list1, "3")) return true;

			//delete if in R2 
			//if preceded by ic, delete if in R2 
			String[] list2 = {"icadora","icador","icaci\u00F3n","icadoras",
					"icadores","icaciones","adora","ador","aci\u00F3n",
					"adoras","adores","aciones"}; 
			if (deleteR2(list2, "4")) return true;
			
			//replace with log if in R2
			String[] list3 = {"log\u00EDa","log\u00EDas"};
			if (replaceR2(list3, "log", "5")) return true;
			
			//replace with u if in R2
			String[] list4 = {"uci\u00F3n","uciones"};
			if (replaceR2(list4, "u", "6")) return true;

			//replace with ente if in R2 
			String[] list5 = {"encia","encias"};
			if (replaceR2(list5, "ent", "7")) return true;


			//if preceded by iv, delete if in R2 
			// (and if further preceded by at, delete if in R2), otherwise,
			// if preceded by os, ic or ad, delete if in R2
			String[] list6 = {"ativamente","ivamente","osamente", 
					"icamente","adamente"};
			if (deleteR2(list6, "8")) return true;

			//delete if in R1 (It's needed to delete from R2 as well)
			String[] list7 = {"amente"};
			String R1Aux = getR1(); 
			if (deleteR1(list7, "9")) return true;
			//return old value
			setR1(R1Aux);
			
			if (deleteR2(list7, "10")) return true;
			
			//delete if in R2
			String[] list8 = {"ablemente","iblemente","mente"};
			if (deleteR2(list8, "11")) return true;
			
			//This rule does not exist at the original algorithm
			String[] list81 = {"mente"};
			if (deleteR1(list81, "11-1")) return true;
			
			//delete if in R2 
			//if preceded by abil, ic or iv, delete if in R2 
			String[] list9 = {"abilidad","abilidades","icidad","icidades",
					"ividad", "ividades","idad","idades"};
			if (deleteR2(list9, "12")) return true;
			
			//delete if in R2 
			//if preceded by at, delete if in R2 
			String[] list10 = {"ativa","ativo","ativas","ativos",
					"iva", "ivo","ivas","ivos"};
			if (deleteR2(list10, "13")) return true;

		} catch (Exception exc) {
			throw new Exception ("Context: step1 method. Error: "+exc.getMessage());
		}
		return false;
	}
	
	/**
	 * Step 2a. Verb suffixes beginning y.
	 * @return
	 * @throws Exception
	 */
	private boolean step2a() throws Exception {
		try {
			String[] list = {"ya","ye","yan","yen","yeron","yendo",
					"yo","y\u00F3","yas","yes","yais","yamos"};
			if (deleteRVCompl(list, "u", "14")) return true;
		} catch (Exception exc) {
			throw new Exception ("Context: step2a method. Error: "+exc.getMessage());
		}
		return false;
	}
	
	/**
	 * Step 2b. Other verb suffixes.
	 * @return
	 * @throws Exception
	 */
	private boolean step2b() throws Exception {
		boolean result = false;
		try {
			String[] list = {
					"ar\u00EDan","ar\u00EDas","ar\u00E1n","ar\u00E1s",
					"ar\u00EDais","ar\u00EDa","ar\u00E9is",
					"ar\u00EDamos","aremos","ar\u00E1","ar\u00E9",
					"er\u00EDan","er\u00EDas","er\u00E1n","er\u00E1s",
					"er\u00EDais","er\u00EDa","er\u00E9is","er\u00EDamos",
					"eremos","er\u00E1","er\u00E9","ir\u00EDan",
					"ir\u00EDas","ir\u00E1n","ir\u00E1s","ir\u00EDais",
					"ir\u00EDa","ir\u00E9is","ir\u00EDamos","iremos",
					"ir\u00E1","ir\u00E9","aba","ada","ida","\u00EDa",
					"ara","iera","ad","ed","id","ase","iese","aste",
					"iste","an","aban","\u00EDan","aran","ieran","asen",
					"iesen","aron","ieron","ado","ido","ando",
					"iendo","i\u00F3","ar","er","ir","as","abas","adas",
					"idas","\u00EDas","aras","ieras","ases","ieses",
					"\u00EDs","\u00E1is","abais","\u00EDais","arais",
					"ierais","aseis","ieseis","asteis","isteis","ados",
					"idos","amos","\u00E1bamos","\u00EDamos","imos",
					"\u00E1ramos","i\u00E9ramos","i\u00E9semos","\u00E1semos"};
			int ctr = findLongest(list, getRV());
			if ((ctr >= 0) && (ctr <= 3)) { //"en","es","\u00E9is","emos" suffixes
				if (deleteRV(list, "15")) {
					if (getRV().endsWith("gu"))
						setRV(getRV().substring(0,getRV().length()-1));
					if ((getRV().trim().equalsIgnoreCase("")) &&
						(getWordRV().endsWith("gu")))
						setWordRV(getWordRV().substring(0,getWordRV().length()-1));
					return true;
				}
			} else {
				if (deleteRV(list, "16")) return true;
			}
			//if (deleteRV(list1, "16")) result = true;

		} catch (Exception exc) {
			throw new Exception ("Context: step2b method. Error: "+exc.getMessage());
		}
		return result;
	}

	/**
	 * Step 3. Residual suffix.
	 * @return
	 * @throws Exception
	 */
	private boolean step3() throws Exception {
		boolean result = false;
		try {
			String[] list = {"os","a","o","\u00E1","\u00ED","\u00F3"};
			if (deleteRV(list, "18")) return true;
			
			String[] list1 = {"e","\u00E9"};
			if (deleteRV(list1, "19")) {
				if (getRV().endsWith("gu"))
					setRV(getRV().substring(0,getRV().length()-1));
				return true;
			}
			
		} catch (Exception exc) {
			throw new Exception ("Context: step3 method. Error: "+exc.getMessage());
		}
		return result;
	}
	
	/**
	 * Stem the input word returning a different word when the process
	 * was successfully applied.
	 * @param pWord input paramenter.
	 * @return the word modified by the stemming process.
	 * @throws Exception
	 */
	public String stem(String pWord) throws Exception {
		try {
			if (pWord.trim().length() <= 1) 
				return Util.removeAccent(pWord); 
			pstep0 = pstep1 = pstep2a = pstep2b = pstep3 = false;
			setWord(""); setR1(""); setR2(""); setWordRV(""); setRV("");
			setPr12(false); setPrv(false); 
			
			setWord(pWord.trim().toLowerCase());
			
			//Call r1, r2 and rv
			rule1(); 
			rule2(); 
			ruleV();
			
			if (isLog()) {
				System.out.println("Word: "+getWord());
				System.out.println("R1: "+getR1());
				System.out.println("R2: "+getR2());
				System.out.println("WordRV: "+getWordRV());
				System.out.println("RV: "+getRV());
			}
			
			if ((getR1().equalsIgnoreCase("")) &&
				(getR2().equalsIgnoreCase("")) &&
				(getRV().equalsIgnoreCase("")))
				return Util.removeAccent(pWord);
				
			pstep0 = step0();
			pstep1 = step1();
			
			//Do step 2a if no ending was removed by step 1. 
			if (!pstep1) pstep2a = step2a();
			
			//Do Step 2b if step 2a was done, but failed to remove a suffix. 
			if ((!pstep1) && (!pstep2a)) pstep2b = step2b();
			
			//Always do step 3.
			pstep3 = step3();

			if (!pstep0 && !pstep1 && !pstep2a && !pstep2b && !pstep3)
				return Util.removeAccent(pWord);
			else if (isPr12())
				return Util.removeAccent(getWord()+getR1()+getR2());
			else
				return Util.removeAccent(getWordRV()+getRV());
		} catch (Exception exc) {
			throw new Exception("Context: stem method. Error: "+exc.getMessage());
		}
	}

}

